/*
    GASON: SQLmap Wrapper for Burpsuite.
    Copyright (C) 2011-2012  Daniel Garcia (cr0hn) | dani@iniqua.com | twitter: @ggdaniel
    Project page: http://code.google.com/p/gason/

    This program is free software; you can redistribute it and/or
    modify it under the terms of the GNU General Public License
    as published by the Free Software Foundation; either version 2
    of the License, or (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA.
 */

/*
 * PluginTab.java
 *
 * Created on 16-feb-2012, 23:17:03
 */

package CustomPlugin.sqlmap;

import java.awt.Color;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.io.PrintWriter;
import java.util.Iterator;
import java.util.List;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.swing.JFileChooser;
import javax.swing.JTabbedPane;
import javax.swing.JTextArea;
import javax.swing.SwingWorker;
import javax.swing.text.BadLocationException;
import javax.swing.text.DefaultHighlighter;
import javax.swing.text.Document;
import javax.swing.text.Highlighter;
import javax.swing.text.JTextComponent;

/**
 *
 * @author Daniel Garcia Garcia (cr0hn) - dani@iniqua.com
 */
public class sqlmapTab extends javax.swing.JPanel implements Runnable {

    Highlighter.HighlightPainter myHighlightPainter = new MyHighlightPainter(Color.YELLOW);
    private JTabbedPane tabpanel;
    private ForkWorker _for;
    private boolean _debug;

    // A private subclass of the default highlight painter
    class MyHighlightPainter extends DefaultHighlighter.DefaultHighlightPainter {
        public MyHighlightPainter(Color color) {
            super(color);
        }
    }

    /** Creates new form PluginTab */
    public sqlmapTab(List command, String URL, JTabbedPane tabPane, boolean  debug) throws IOException {
        this.tabpanel = tabPane;
        this._debug = debug;
        initComponents();

        this.txt_URL.setText(URL);

        // Run process
        ProcessBuilder builder = new ProcessBuilder(command);
        builder.start();

        builder.redirectErrorStream(true);
        this._for = new ForkWorker(this.txt_console, builder, _debug);
    }

    @Override
    public void run() {
        this._for.execute();
    }

    /** This method is called from within the constructor to
     * initialize the form.
     * WARNING: Do NOT modify this code. The content of this method is
     * always regenerated by the Form Editor.
     */
    @SuppressWarnings("unchecked")
    // <editor-fold defaultstate="collapsed" desc="Generated Code">//GEN-BEGIN:initComponents
    private void initComponents() {

        jScrollPane1 = new javax.swing.JScrollPane();
        txt_console = new javax.swing.JTextArea();
        jLabel1 = new javax.swing.JLabel();
        txt_search = new javax.swing.JTextField();
        btn_select_file = new javax.swing.JButton();
        btn_close = new javax.swing.JButton();
        jLabel2 = new javax.swing.JLabel();
        txt_URL = new javax.swing.JTextField();

        setPreferredSize(new java.awt.Dimension(550, 640));
        setLayout(null);

        txt_console.setBackground(new java.awt.Color(0, 0, 0));
        txt_console.setColumns(20);
        txt_console.setFont(new java.awt.Font("Dialog", 0, 14));
        txt_console.setForeground(new java.awt.Color(102, 204, 0));
        txt_console.setLineWrap(true);
        txt_console.setRows(5);
        txt_console.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyPressed(java.awt.event.KeyEvent evt) {
                txt_consoleKeyPressed(evt);
            }
        });
        jScrollPane1.setViewportView(txt_console);

        add(jScrollPane1);
        jScrollPane1.setBounds(4, 35, 580, 530);

        jLabel1.setText("Search:");
        add(jLabel1);
        jLabel1.setBounds(10, 570, 43, 15);

        txt_search.addKeyListener(new java.awt.event.KeyAdapter() {
            public void keyReleased(java.awt.event.KeyEvent evt) {
                txt_searchKeyReleased(evt);
            }
        });
        add(txt_search);
        txt_search.setBounds(60, 570, 520, 20);

        btn_select_file.setText("Save to file...");
        btn_select_file.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_select_fileActionPerformed(evt);
            }
        });
        add(btn_select_file);
        btn_select_file.setBounds(350, 600, 120, 20);

        btn_close.setText("Close tab");
        btn_close.addActionListener(new java.awt.event.ActionListener() {
            public void actionPerformed(java.awt.event.ActionEvent evt) {
                btn_closeActionPerformed(evt);
            }
        });
        add(btn_close);
        btn_close.setBounds(480, 600, 93, 20);

        jLabel2.setText("URL:");
        add(jLabel2);
        jLabel2.setBounds(0, 10, 27, 15);

        txt_URL.setEditable(false);
        add(txt_URL);
        txt_URL.setBounds(30, 10, 550, 19);
    }// </editor-fold>//GEN-END:initComponents

    private void btn_select_fileActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_select_fileActionPerformed
        JFileChooser jfc = new JFileChooser();
        int rt = jfc.showSaveDialog(this);
        
        if (rt == JFileChooser.APPROVE_OPTION)
        {
            PrintWriter ou = null;
            try {
                ou = new PrintWriter(new FileWriter(jfc.getSelectedFile().getName()));
                ou.write(txt_console.getText());
                ou.close();
            } catch (IOException ex) {
                Logger.getLogger(sqlmapTab.class.getName()).log(Level.SEVERE, null, ex);
            } finally {
                ou.close();
            }

        }
    }//GEN-LAST:event_btn_select_fileActionPerformed

    private void btn_closeActionPerformed(java.awt.event.ActionEvent evt) {//GEN-FIRST:event_btn_closeActionPerformed
        this.tabpanel.remove(this);
    }//GEN-LAST:event_btn_closeActionPerformed

    private void txt_consoleKeyPressed(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txt_consoleKeyPressed
        this._for.Update(evt.getKeyChar());
    }//GEN-LAST:event_txt_consoleKeyPressed

    private void txt_searchKeyReleased(java.awt.event.KeyEvent evt) {//GEN-FIRST:event_txt_searchKeyReleased
        removeHighlights(txt_console);
        if(!txt_search.getText().isEmpty())
            highlight(txt_console, txt_search.getText());
    }//GEN-LAST:event_txt_searchKeyReleased


    /**
     * This method highlights a text found in a jtextpane
     *
     * @param textComp: Text pane what contains text
     * @param pattern: Pattern to find into text pane
     */
    private void highlight(JTextComponent textComp, String pattern) {
        // First remove all old highlights
        removeHighlights(textComp);

        Highlighter hilite = textComp.getHighlighter();
        Document doc = textComp.getDocument();
        String text = null;
        try {
            text = doc.getText(0, doc.getLength());
        } catch (BadLocationException ex) {
            Logger.getLogger(sqlmapTab.class.getName()).log(Level.SEVERE, null, ex);
        }
        int pos = 0;

        // Search for pattern
        while ((pos = text.toLowerCase().indexOf(pattern.toLowerCase(), pos)) >= 0) {
            try {
                // Create highlighter using private painter and apply around pattern
                hilite.addHighlight(pos, pos + pattern.length(), myHighlightPainter);
            } catch (BadLocationException ex) {
                Logger.getLogger(sqlmapTab.class.getName()).log(Level.SEVERE, null, ex);
            }
            pos += pattern.length();
        }
    }

    /**
     * This method remove higtlights from a jtextpane
     *
     * @param textComp: Text pane what contains text
     */
    private void removeHighlights(JTextComponent textComp) {
        Highlighter hilite = textComp.getHighlighter();
        Highlighter.Highlight[] hilites = hilite.getHighlights();

        for (int i=0; i<hilites.length; i++) {
            if (hilites[i].getPainter() instanceof MyHighlightPainter) {
                hilite.removeHighlight(hilites[i]);
            }
        }
    }


    // Variables declaration - do not modify//GEN-BEGIN:variables
    private javax.swing.JButton btn_close;
    private javax.swing.JButton btn_select_file;
    private javax.swing.JLabel jLabel1;
    private javax.swing.JLabel jLabel2;
    private javax.swing.JScrollPane jScrollPane1;
    private javax.swing.JTextField txt_URL;
    private javax.swing.JTextArea txt_console;
    private javax.swing.JTextField txt_search;
    // End of variables declaration//GEN-END:variables

}


/**
 * This class execute a command in new thread and display results into jtextpane
 * 
 * @author http://www.onyxbits.de/content/executing-child-process-and-redirecting-output-jtextarea
 */
class ForkWorker extends SwingWorker<String,String> implements Runnable {

    private boolean  _debug;
    private JTextArea output; // Where to redirect STDERR & STDOUT to
    private ProcessBuilder builder;
    private OutputStream input;

    public ForkWorker(JTextArea output, ProcessBuilder builder, boolean  debug) {
        this._debug = debug;
        this.output=output;
        this.builder= builder;
    }

    /**
     * This method is called when there is new info to display in text pane.
     *
     * @param chunks
     */
    @Override
    protected void process(java.util.List<String> chunks) {
        // Done on the event thread
        Iterator<String> it = chunks.iterator();
        while (it.hasNext()) {
          output.append(it.next());
        }
    }

    /**
     * This function is called when we want to send some info to process
     *
     * @param text_: Char to write
     */
    public void Update(char text_)
    {
        if(this.input != null)
            try {
                this.input.write(text_);
                this.input.flush();
        } catch (IOException ex) {
            Logger.getLogger(ForkWorker.class.getName()).log(Level.SEVERE, null, ex);
        }
    }

    /**
     * This method start with execution of process
     * 
     */
    public String doInBackground() {
        Process process = null;
        try {
            process = builder.start();
            InputStream res = process.getInputStream();
            this.input = process.getOutputStream();
            
            byte[] buffer = new byte[100];
            int len;
            while ( (len=res.read(buffer,0,buffer.length))!=-1) {

                publish(new String(buffer,0,len,"ISO-8859-1"));

                if (isCancelled()) {
                    process.destroy();
                    return "";
                }
            }
            this.input.close();
            this.input = null;
        }
        catch (Exception e) {
            if(this._debug)
                System.out.println("[Debug] Exception while executing sqlmap:" + e.toString());
            process.destroy();
            try {
                this.input.close();
            } catch (IOException ex) {
                if(this._debug)
                    System.out.println("[Debug] Exception while executing sqlmap:" + ex.toString());
            }
            this.input = null;
        }
        return "";  // Don't care
    }

    /**
     * This method is called when process are finish.
     */
    @Override
    protected void done() {
        // Done on the swing event thread
        output.append("\n--- EXECUTION IS COMPLETE ---");
    }
}